/*
 *  Copyright (C) 2011 Jaime Pavlich-Mariscal
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package cl.ucn.disc.biblio.refcluster.util;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.TreeMap;

public class MultiCounter<T> implements Set<T>{
	private TreeMap<T,ItemCounter<T>> counter = new TreeMap<T, ItemCounter<T>>();
	private PriorityQueue<ItemCounter<T>> orderedCounters;
	

	private boolean includeNulls;
	
	
	public static class ItemCounter<T> {
		public ItemCounter(T element, Integer count) {
			super();
			this.element = element;
			this.count = count;
		}
		public T element;
		public Integer count;
		@Override
		public String toString() {
			return "[" + element + ":" + count + "]";
		}
	}
	
	public MultiCounter(Comparator<ItemCounter<T>> comparator, boolean excludeNulls) {
		orderedCounters = new PriorityQueue<ItemCounter<T>>(10, comparator);
		this.includeNulls=excludeNulls;
	}
	
	@Override
	public boolean add(T elem) {
		if (!includeNulls && elem == null) return false;
		
		ItemCounter<T> ic = counter.remove(elem);
		orderedCounters.remove(ic);
		if (ic == null) {
			ic = new ItemCounter<T>(elem,1);
		} else {
			ic.count++;
		}
		counter.put(elem,ic);
		orderedCounters.add(ic);
		return true;
		
	}
	
	public int getCount(T elem) {
		ItemCounter<T> ic = counter.get(elem);
		if (ic == null) {
			return 0;
		} else {
			return ic.count;
		}
	}
	
	@Override
	public Iterator<T> iterator() {
		return counter.keySet().iterator();
	}
	
	public Iterator<ItemCounter<T>> orderedCountersIterator() {
		return orderedCounters.iterator();
	}

	
	@Override
	public boolean addAll(Collection<? extends T> c) {
		for (T e : c) {
			add(e);
		}
		return true;
	}

	@Override
	public void clear() {
		counter.clear();
		orderedCounters.clear();
		
	}

	@Override
	public boolean contains(Object o) {
		return counter.containsKey(o);
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean isEmpty() {
		return orderedCounters.isEmpty();
	}

	@Override
	public boolean remove(Object o) {
		throw new UnsupportedOperationException();

	}

	@Override
	public boolean removeAll(Collection<?> c) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		throw new UnsupportedOperationException();
	}

	@Override
	public int size() {
		throw new UnsupportedOperationException();
		
	}

	@Override
	public Object[] toArray() {
		throw new UnsupportedOperationException();
	}

	@SuppressWarnings("hiding")
	@Override
	public <T> T[] toArray(T[] a) {
		throw new UnsupportedOperationException();
	}

	@Override
	public String toString() {
		return orderedCounters.toString();
	}
}
